DNS 服务的作用
- 服务发现:自动为 Service 和 Pod 创建 DNS 记录,允许通过域名访问服务,而非依赖 IP。
- 动态更新:实时响应 Service 和 Pod 的变化(如扩缩容、IP 变更)。
- 命名空间隔离:支持跨命名空间的服务访问。
DNS自动注入
每个 Pod 的 /etc/resolv.conf 文件自动配置:
nameserver 10.96.0.10 # CoreDNS 的 ClusterIP
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
nameserver:指向 CoreDNS 服务。
search 域:简化域名输入(如 my-svc 自动补全为 my-svc.<namespace>.svc.cluster.local)。
CoreDNS解析流程
以 Pod 中请求 nginx.default.svc.cluster.local 为例,流程如下:
- Pod 内应用发出 DNS 请求,通过core dns自动注入的配置:nameserver 10.96.0.10去找CoreDNS 服务。
查看pod内的/etc/resolv.conf文件
cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
- CoreDNS 的53端口接收到请求(udp协议)之后进行kubernetes 插件处理,若找到,直接返回 IP,未找到则进入 forward 插件。
CoreDNS 的记录来源取决于插件配置
kubectl edit cm coredns -n kube-system
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
creationTimestamp: "2025-05-08T03:05:18Z"
name: coredns
namespace: kube-system
resourceVersion: "245"
uid: 4b6b7437-a982-4fd3-8c89-e40d6d589c95
各插件含义如下:
errors 打印错误日志到 stdout
health 提供健康检查 endpoint
kubernetes 查询 K8s 中的 Service、Pod 域名,自动解析为 ClusterIP 或 Pod IP
forward 将未知的域名请求转发到上游 DNS(比如 /etc/resolv.conf 中的)
cache 缓存 DNS 查询结果,cache 30 表示缓存30s
loop 检测请求是否在本地循环(防止死循环)
reload 当 Corefile 修改时自动重新加载
loadbalance 对多记录进行轮询返回
解析kubernetes 插件配置:
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
cluster.local:这是 Kubernetes 默认的服务域名后缀,表示集群内的服务名(例如 my-service.cluster.local)。
in-addr.arpa 和 ip6.arpa:这用于反向 DNS 查找。
pods insecure:允许 Pod 名的 DNS 查询,但不对其进行验证。
fallthrough in-addr.arpa ip6.arpa:如果请求是反向 DNS 查找并且没有匹配的记录,CoreDNS 会继续向下游 DNS 服务器发起请求。
ttl 30:设置 Kubernetes 服务和 Pod DNS 记录的 TTL(缓存时间)为 30 秒,表示缓存 DNS 记录 30 秒。
- forward将请求转发到 /etc/resolv.conf指定的 DNS,比如 8.8.8.8。
解析forward插件配置:
forward . /etc/resolv.conf {
max_concurrent 1000
}
将无法解析的 DNS 查询转发到 coredns容器的resolv.conf 中的配置的上游 DNS 服务器。这是一个“转发”策略,max_concurrent 1000 表示最多同时处理 1000 个并发的转发请求。
默认coredns容器的resolv.conf和conedns pod所在的宿主机的resolv.conf一样
进入coredns容器查看resolv.conf文件:
docker run -it --net=container:$ID --pid=container:$ID --volumes-from=$ID alpine sh(将$ID换为容器id)
cat /etc/resolv.conf
也可以写为:
forward . 8.8.8.8{
max_concurrent 1000
}
将无法解析的 DNS 查询转发到 8.8.8.8 服务器
- 结果返回客户端
CoreDNS的缓存问题
cache配置中默认有一个插件:cache 30 ,表示缓存30s,那么会诞生出问题:缓存造成延迟更新
- Service 名称被删除 + 新建
- 此时虽然名字一样,但实际上是两个不同的对象(新建了 Service),其 ClusterIP 可能不同。
- 如果业务 Pod 在最近30s内发出 DNS 查询,而 CoreDNS 已缓存旧的 svc记录,会因为旧记录仍保留在缓存中而导致解析失败或解析出旧 IP。
- 这时即使新服务已经生效了,CoreDNS 可能要等 30 秒缓存过期,才会重新查询。
- Service 的 Endpoints 更新(Pod 被替换)
- Deployment 滚动更新
- 后端 Pod IP 变化
- 如果你配置了 cache 30,它可能缓存的是旧的 Pod IP 地址,直到缓存失效才更新。
如何解决这个问题?
- 降低 cache 时间,cache 5
- 细粒度设置成功与失败缓存时间
cache {
success 10
denial 2
}
设置 denial 2,这样 CoreDNS 在失败后只缓存 2 秒,2 秒后会重新查一次新的结果,就能解析到新创建的 Service。
- 关闭缓存,# 注释掉 cache 插件行
Service 的 DNS 记录规则
普通 Service(ClusterIP/NodePort)
- DNS 记录格式:service-name.namespace.svc.cluster.local,或者直接service-name(依赖 search 域,只能同一个命名空间内)
- 解析目标:Service 的 ClusterIP。
- 端口访问:DNS 仅解析 IP,端口需显式指定(如 http://my-svc:8080)。
无头服务(Headless Service)
- 定义方式:设置 clusterIP: None。
- 解析目标:直接解析到后端 Pod 的 IP(而非 Service 的虚拟 IP)。
适用场景:
- 有状态应用(如数据库集群)需直接访问 Pod。
- 客户端需自行实现负载均衡或选择特定实例。
DNS 记录格式:(需配合 StatefulSet):pod-name.service-name.namespace.svc.cluster.local